package com.irssproject.app.service.lectorRSS.impl;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;

import net.htmlparser.jericho.Source;

import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.irssproject.app.bean.lectorRSS.Etiqueta;
import com.irssproject.app.bean.lectorRSS.Feed;
import com.irssproject.app.bean.lectorRSS.Item;
import com.irssproject.app.bean.lectorRSS.Lectura;
import com.irssproject.app.bean.lectorRSS.Subscripcio;
import com.irssproject.app.bean.main.Usuari;
import com.irssproject.app.dao.lectorRSS.iface.EtiquetaDAO;
import com.irssproject.app.dao.lectorRSS.iface.FeedDAO;
import com.irssproject.app.dao.lectorRSS.iface.SubscripcioDAO;
import com.irssproject.app.service.lectorRSS.iface.SubscripcioService;
import com.irssproject.app.utils.Constants;
import com.sun.syndication.feed.synd.SyndContent;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.XmlReader;

@Transactional(
		propagation = Propagation.REQUIRED,
		isolation = Isolation.DEFAULT		
)
public class SubscripcioServiceImpl implements SubscripcioService{
	
	Logger logger = Logger.getLogger(SubscripcioServiceImpl.class.getName());
	SubscripcioDAO subscripcioDAO;
	FeedDAO feedDAO;
	EtiquetaDAO etiquetaDAO;

	public void setEtiquetaDAO(EtiquetaDAO etiquetaDAO) 
	{	
		this.etiquetaDAO = etiquetaDAO;
	}

	public void setFeedDAO(FeedDAO feedDAO) 
	{
		this.feedDAO = feedDAO;
	}

	public void setSubscripcioDAO(SubscripcioDAO subscripcioDAO) 
	{
		this.subscripcioDAO = subscripcioDAO;
	}


	public void insertSubscripcio(Usuari usuari, Feed feed, Etiqueta etiqueta, List<Item> items) throws Exception 
	{
		Subscripcio subscripcio = new Subscripcio();
	
		subscripcio.setUsuari(usuari);
		
		Feed f = feedDAO.getFeedByLink(feed);
		if (f !=null)
		{
			subscripcio.setFeed(f);
		}
		else
		{
			feedDAO.insertFeed(feed);
			subscripcio.setFeed(feed);
		}
		
		if (etiqueta!=null)
		{
			Etiqueta e = etiquetaDAO.getEtiquetaByNom(etiqueta);
			if (e!=null) 
			{
				subscripcio.setEtiqueta(e);
			}
			else
			{
				etiquetaDAO.insertEtiqueta(etiqueta);
				subscripcio.setEtiqueta(etiqueta);
			}
			
		}
		
		subscripcio.setDataSubscripcio(Calendar.getInstance().getTime());
		subscripcio.setNumItemsNoLlegits(items.size());
		
		List<Lectura> liLectures = new ArrayList<Lectura>();
		
		Iterator<Item> it = items.iterator();
		Lectura le;
		Item item, itemExisting;
		while(it.hasNext())
		{
			le = new Lectura();

			item = (Item)it.next();
			itemExisting = subscripcioDAO.getItemByLink(item.getLink());
			
			if (itemExisting!=null)
			{
				le.setItem(itemExisting);
			}
			else 
			{
				Long id = subscripcioDAO.insertItem(item);
				item.setId(id);
				le.setItem(item);
			}
			
			le.setLlegida(false);
			le.setTemps(0);
			le.setRellevancia(0);
			le.setValorada(false);
			le.setDataAfegida(item.getDataPublicacio());
			liLectures.add(le);
		}
		
		subscripcio.setLectures(liLectures);
		
		subscripcioDAO.insertSubscripcio(subscripcio);
	}
	
	public List<Item> getFeedEntries(Feed feed) throws Exception
	{
		List<Item> items = new ArrayList<Item>();
		try {
			URL feedUrl = new URL(feed.getLink());
	
			final SyndFeedInput input = new SyndFeedInput();
	
			final SyndFeed feedRSS = input.build(new XmlReader(feedUrl));
	
			Iterator entry = feedRSS.getEntries().iterator();
			Item entrada;
			
			while (entry.hasNext()){
				entrada = new Item();
	
				SyndEntry en = (SyndEntry)entry.next();
				entrada.setTitol(en.getTitle());
				entrada.setLink(en.getLink());
				entrada.setDataPublicacio(en.getPublishedDate());
				
				if (en.getContents().size()>0){
					entrada.setContingut(((SyndContent)en.getContents().get(0)).getValue());
				}
				else if (en.getDescription() != null){
					entrada.setContingut(en.getDescription().getValue());
				}
				items.add(entrada);
			}
		}
		catch(IllegalArgumentException iae)
		{
			throw new Exception(Constants.EXCEPTION_ILLEGAL_FEED);
		}
		catch(FeedException fe)
		{
			throw new Exception(Constants.EXCEPTION_GENERIC_FEED);
		}
		catch(MalformedURLException mue)
		{
			throw new Exception(Constants.EXCEPTION_MALFORMED_FEED_URL);
		}
		return items;
	}

	public void refrescarSubscripcio(Long idSubscripcio) 
	{
		Item entry = new Item();
		
		List<Item> listNousItems = new ArrayList<Item>();

		Subscripcio subscripcio = subscripcioDAO.getSubscripcioById(idSubscripcio);
		
		Date dataDarrerItem = subscripcioDAO.getDarreraDataPublicacio(subscripcio);
			
		try{
			URL feedUrl = new URL(subscripcio.getFeed().getLink());
			final SyndFeedInput input = new SyndFeedInput();
			final SyndFeed feedRSS = input.build(new XmlReader(feedUrl));

			Iterator entries = feedRSS.getEntries().iterator();

			int cont=0;

			while (entries.hasNext()){
				entry = new Item();

				SyndEntry en = (SyndEntry)entries.next();
				entry.setTitol(en.getTitle());
				entry.setLink(en.getLink());
				entry.setDataPublicacio(en.getPublishedDate());
				
				if (en.getContents().size()>0){
					entry.setContingut(((SyndContent)en.getContents().get(0)).getValue());
				}
				else if (en.getDescription() != null){
					entry.setContingut(en.getDescription().getValue());
				}
					
				//Si la data de publicacio de la entrada es mes nova que la data de l'ultima lectura
				//l'afegim a la llista de no llegits
				if (entry.getDataPublicacio().compareTo(dataDarrerItem)>0)
				{
					logger.info("Adding new item from feed "+subscripcio.getFeed().getTitol()
								+"  Item name: "+entry.getTitol()+". Published data: "+entry.getDataPublicacio());
					listNousItems.add(entry);
					cont+=1;
				}
			}
								
			if (listNousItems.size()>0){
				
				
				List<Lectura> liLectures = new ArrayList<Lectura>();
				
				Iterator it = listNousItems.iterator();
				Lectura le;
				Item item, itemExisting;
				while(it.hasNext())
				{
					le = new Lectura();

					item = (Item)it.next();
					itemExisting = subscripcioDAO.getItemByLink(item.getLink());
					
					if (itemExisting!=null)
					{
						le.setItem(itemExisting);
					}
					else 
					{
						Long id = subscripcioDAO.insertItem(item);
						item.setId(id);
						le.setItem(item);
					}
					
					le.setLlegida(false);
					le.setTemps(0);
					le.setRellevancia(0);
					le.setValorada(false);
					le.setDataAfegida(item.getDataPublicacio());
					liLectures.add(le);
				}
							
				subscripcio.addLecturesCollection(liLectures);

				subscripcioDAO.refreshSubscripcio(subscripcio);
			}
		}
		catch (Exception e) {
			e.printStackTrace();
		}		
	}

	public void eliminarSubscripcio(Long idSubscripcio) 
	{
		subscripcioDAO.deleteSubscripcio(idSubscripcio);	
	}


	public List<Subscripcio> getListSubscripcions(Usuari usuari) 
	{
		return subscripcioDAO.getListSubscripcions(usuari);		
	}


	public List<Etiqueta> getListEtiquetes(Usuari usuari) 
	{
		return subscripcioDAO.getListEtiquetes(usuari);
	}



	public void marcarLecturaLlegida(Long idLectura) 
	{
		Lectura lectura = subscripcioDAO.getLecturaById(idLectura);
		lectura.setLlegida(true);
		lectura.getSubscripcio().setNumItemsNoLlegits(lectura.getSubscripcio().getNumItemsNoLlegits()-1);
		subscripcioDAO.marcarLecturaLlegida(lectura);
	}


	public List<Etiqueta> getListEtiquetes() 
	{
		return etiquetaDAO.getListEtiquetes();
	}


	public void definirRellevanciaDeLectura(Lectura lectura)
	{
		Item itemComplet = lectura.getItem();
		
		Source source=new Source(itemComplet.getContingut());
		String contentDirty = itemComplet.getContingut();
		String content = source.getTextExtractor().setIncludeAttributes(true).toString();
		
		int contentLength = content.length();
		float tempsMinimActual = (((float)contentLength)*Constants.TEMPS_MINIM_LECTURA)/1000;
		float tempsMaximActual = (((float)contentLength)*Constants.TEMPS_MAXIM_LECTURA)/1000;

		if (lectura.isValorada()==true)
		{
			if (lectura.getTemps() > tempsMinimActual && lectura.getTemps() < tempsMaximActual)
			{
				lectura.setRellevancia(3);
			}
			else 
			{
				if (contentDirty.contains(Constants.EMBEDED_YOUTUBE_SEQ) || contentDirty.contains(Constants.SHOCKWAVE_FLASH_SEQ))
				{
					lectura.setRellevancia(3);
				}
				else
				{
					lectura.setRellevancia(2);
				}
			}
		}
		else
		{
			if (lectura.getTemps() > tempsMinimActual && lectura.getTemps() < tempsMaximActual)
			{
				lectura.setRellevancia(1);
			}
			else 
			{
				if (contentDirty.contains(Constants.EMBEDED_YOUTUBE_SEQ) || contentDirty.contains(Constants.SHOCKWAVE_FLASH_SEQ))
				{
					lectura.setRellevancia(1);
				}
				else
				{
					lectura.setRellevancia(0);
				}
			}

			
		}
		subscripcioDAO.definirRellevanciaDeLectura(lectura);				
	}


	public List<Lectura> mostrarLecturesNoLlegides(Long idSubscripcio) 
	{	
		Subscripcio subscripcio = subscripcioDAO.getSubscripcioById(new Long(idSubscripcio));
		List<Lectura> llistaLectures = subscripcioDAO.obtenirLecturesSubscripcio(subscripcio);
		return llistaLectures;
	}


	public List<Lectura> mostrarTotesLectures(Long idSubscripcio) 
	{
		Subscripcio subscripcio = subscripcioDAO.getSubscripcioById(new Long(idSubscripcio));
		return subscripcioDAO.obtenirLecturesSubscripcio(subscripcio);
		
	}


	public List<Lectura> mostrarLecturesVotades(Usuari usuari) 
	{
		return subscripcioDAO.getLecturesVotades(usuari);
	}


	public List<Subscripcio> getListSubscripcionsPerEtiqueta(Usuari usuari,
			Etiqueta etiqueta) 
	{
		return subscripcioDAO.getListSubscripcionsPerEtiqueta(usuari,etiqueta);
	}





	public Feed readRSSFeed(Feed feed) throws Exception
	{
		Feed feedOut = new Feed();
		
		try
		{
			URL feedUrl = new URL(feed.getLink());
			final SyndFeedInput input = new SyndFeedInput();
	
			final SyndFeed feedRSS = input.build(new XmlReader(feedUrl));
	
			feedOut.setTitol(feedRSS.getTitle());
			feedOut.setLink(feed.getLink());
	
		}
		catch(IllegalArgumentException iae)
		{
			throw new Exception(Constants.EXCEPTION_ILLEGAL_FEED);
		}
		catch(FeedException fe)
		{
			throw new Exception(Constants.EXCEPTION_GENERIC_FEED);
		}
		catch(MalformedURLException mue)
		{
			throw new Exception(Constants.EXCEPTION_MALFORMED_FEED_URL);
		}
		
		return feedOut;
	}


	public Item getItem(Subscripcio subscripcio, Item item) {
		return subscripcioDAO.getItem(item);
	}


	public Integer getNumItemsSubscripcio(Subscripcio subscripcio) 
	{
		return subscripcioDAO.getNumItemsSubscripcio(subscripcio);
	}

	public boolean usuariTeFeedSubscrit(Usuari usuari, Feed feed) 
	{
		return subscripcioDAO.usuariTeFeedSubscrit(usuari, feed);
	}

	public Subscripcio getSubscripcioById(Long idSubscripcio) 
	{
		return subscripcioDAO.getSubscripcioById(idSubscripcio);
	}

	public Lectura getLecturaById(Long idLectura) 
	{
		return subscripcioDAO.getLecturaById(idLectura);
	}

	public boolean marcarLlegidaONoLlegida(Long idLectura) 
	{
		return subscripcioDAO.marcarLlegidaONoLlegida(idLectura);
	}

	public boolean valorarLectura(Long idLectura) 
	{
		return subscripcioDAO.valorarLectura(idLectura);
	}

	public void marcarTotesLecturesLlegides(Long idSubscripcio) 
	{
		subscripcioDAO.marcarTotesLecturesLlegides(idSubscripcio);		
	}
}
